package com.logic.landseaserver.service.impl;

import java.io.*;
import java.util.HashMap;

import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.enums.SystemCodeEnum;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.ws.dto.LocalSignDTOTest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.logic.common.exception.BusinessException;
import com.logic.common.ws.dto.system.FileDTO;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.enums.SendMsgCodeEnum;
import com.logic.landseaserver.common.exception.LandseaBusinessException;
import com.logic.landseaserver.common.util.IconImage;
import com.logic.landseaserver.common.util.ImageZip;
import com.logic.landseaserver.common.util.PDF2Image;
import com.logic.landseaserver.domain.ConfigurationQiyuesuo;
import com.logic.landseaserver.domain.Contract;
import com.logic.landseaserver.domain.Deposit;
import com.logic.landseaserver.domain.VerificationCode;
import com.logic.landseaserver.service.IConfigurationQiyuesuoService;
import com.logic.landseaserver.service.IContractService;
import com.logic.landseaserver.service.IDepositService;
import com.logic.landseaserver.service.ILsLocalSignService;
import com.logic.landseaserver.service.ISendSmsService;
import com.logic.landseaserver.ws.dto.ContractDTO;
import com.logic.landseaserver.ws.dto.DepositDTO;
import com.logic.landseaserver.ws.dto.LocalSignDTO;
import com.qiyuesuo.sdk.SDKClient;
import com.qiyuesuo.sdk.api.LocalSignService;
import com.qiyuesuo.sdk.api.SealService;
import com.qiyuesuo.sdk.impl.LocalSignServiceImpl;
import com.qiyuesuo.sdk.impl.SealServiceImpl;
import com.qiyuesuo.sdk.sign.Stamper;
import com.qiyuesuo.sdk.signer.Person;
import com.qiyuesuo.sdk.signer.PaperType;
@Service
public class LsLocalSignServiceImpl implements ILsLocalSignService, EnvironmentAware {

	private static final Logger logger = LoggerFactory.getLogger(LsLocalSignServiceImpl.class);

	@Autowired
	private IContractService contractService;

	@Autowired
	private IDepositService depositService;

	@Autowired
	private IConfigurationQiyuesuoService configurationQiyuesuoServiceImpl;

	@Autowired
	private ISendSmsService sendSmsService;
	@Autowired
	private ContractReadMapper contractReadMapper;

	private static RelaxedPropertyResolver propertyResolverFile;
	private static final String ENV_FILE_PATH = "logic.file.path.";
	private static final String LOCAL_PATH = "local";
	private static final String CONTRACT_PATH = "contract_path";
	private static final String DEPOSIT_PATH = "dipositPath";

	private static RelaxedPropertyResolver propertyResolverSeal;
	private static final String ENV_SEAL = "logic.seal.qiyuesuo.";
	private static final String URL = "url";
	private static final String ACCESS_KEY = "accessKey";
	private static final String ACCESS_SECRET = "accessSecret";
	private static final String SEAL_ID = "sealId";
	private static final String ICON_NAME = "iconName";

	private static final String COORDINATE_DEPOSIT_COMPANY_PAGE = "coordinate.deposit.company.page";
	private static final String COORDINATE_DEPOSIT_COMPANY_OFFSETX = "coordinate.deposit.company.offsetX";
	private static final String COORDINATE_DEPOSIT_COMPANY_OFFSETY = "coordinate.deposit.company.offsetY";
	private static final String COORDINATE_DEPOSIT_PERSON_PAGE = "coordinate.deposit.person.page";
	private static final String COORDINATE_DEPOSIT_PERSON_OFFSETX = "coordinate.deposit.person.offsetX";
	private static final String COORDINATE_DEPOSIT_PERSON_OFFSETY = "coordinate.deposit.person.offsetY";


	private static final String COORDINATE_CONTRACT_COMPANY_PAGE = "coordinate.contract.company.page";
	private static final String COORDINATE_CONTRACT_COMPANY_OFFSETX = "coordinate.contract.company.offsetX";
	private static final String COORDINATE_CONTRACT_COMPANY_OFFSETY = "coordinate.contract.company.offsetY";
	private static final String COORDINATE_CONTRACT_PERSON_PAGE = "coordinate.contract.person.page";
	private static final String COORDINATE_CONTRACT_PERSON_OFFSETX = "coordinate.contract.person.offsetX";
	private static final String COORDINATE_CONTRACT_PERSON_OFFSETY = "coordinate.contract.person.offsetY";

	private final int iconPositionWidth = 0;
	private final int  iconPpositionHeight = 1800;


	//	@Bean
	public SDKClient sdkClient(String accessKey, String accessSecret){
		String url = propertyResolverSeal.getProperty(URL, String.class, null);
//		String accessKey = propertyResolverSeal.getProperty(ACCESS_KEY, String.class, null);
//		String accessSecret = propertyResolverSeal.getProperty(ACCESS_SECRET, String.class, null);
		return new SDKClient(url,accessKey,accessSecret);
	}

	//	@Bean
	public LocalSignService LocalSignService(SDKClient sdkClient){
		return new LocalSignServiceImpl(sdkClient);
	}

	//	@Bean
	public SealService sealService(SDKClient sdkClient){
		return new SealServiceImpl(sdkClient);
	}

	private String localSignDeposit(LocalSignDTO localSignDTO) throws BusinessException,LandseaBusinessException, IOException {
		Integer depositId = localSignDTO.getDepositId();
		DepositDTO depositDTO = (DepositDTO) depositService.get(depositId);
		Integer prjId = depositDTO.getPrjId();
		ConfigurationQiyuesuo configurationQiyuesuo = (ConfigurationQiyuesuo) configurationQiyuesuoServiceImpl.get(prjId);
		if (configurationQiyuesuo == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.CONFIGURATION_QIYUESUO_ERROE);
		}
		String accessToken = configurationQiyuesuo.getAccessToken();
		String accessSecret = configurationQiyuesuo.getAccessSecret();
		Long sealId = configurationQiyuesuo.getSealId();
		if (StringUtils.isBlank(accessToken)
				|| StringUtils.isBlank(accessSecret)
				|| sealId == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.CONFIGURATION_QIYUESUO_ERROE);
		}
		SDKClient sdkClient = this.sdkClient(accessToken, accessSecret);
		LocalSignService localSignService = this.LocalSignService(sdkClient);
		FileDTO depositPdf = depositDTO.getPdf();
		String localFullPath = depositPdf.getLocalFullPath();
		String remoteFullPath = depositPdf.getFullPath();
		String userName = depositDTO.getUserName();
		String cellphone = depositDTO.getCellPhone();
		String depositPath = propertyResolverFile.getProperty(DEPOSIT_PATH, String.class, null);
		String localPath = propertyResolverFile.getProperty(LOCAL_PATH, String.class, null);
		String localFilePath = localPath + "/" + depositPath + "/";
		//平台签署有外观签名
		InputStream platformStamperInput = new FileInputStream(new File(localFullPath));
		String localPlatFormStamperFileName = "qiyuesuo-local-platform-stamper.pdf";
		String localPlatFormStamperFileFullPath = localFilePath + localPlatFormStamperFileName;
		OutputStream platformStamperOut = new FileOutputStream(new File(localPlatFormStamperFileFullPath));
		//指定签名页码和坐标，确定签名位置
		//Stamper stamper = new Stamper(1, 0.1f, 0.1f);
		//根据关键字确定签名位置，若找到多个关键字则只在第一个关键字出现的位置签署，若没有出现关键字则抛出异常
		Stamper keywordStamper = new Stamper(propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_COMPANY_PAGE, Integer.class, null),
				propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_COMPANY_OFFSETX, Float.class, null),
				propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_COMPANY_OFFSETY, Float.class, null));
//			Long sealId = propertyResolverSeal.getProperty(SEAL_ID, Long.class, null);//印章ID，在云平台维护
		localSignService.sign(platformStamperInput, platformStamperOut,sealId ,keywordStamper);
		logger.info("平台签署带外观签名完成.");
		//========================================================================
		//个人用户签署有外观签名
		String localPersonStamperFileName = "qiyuesuo-local-person-stamper.pdf";
		String localPersonStamperFileFullPath = localFilePath + localPersonStamperFileName;
		InputStream personStamperInput = new FileInputStream(new File(localPlatFormStamperFileFullPath));
		OutputStream personStamperOut = new FileOutputStream(new File(localPersonStamperFileFullPath));
		//实例化个人用户信息，姓名（name）必须, 身份信息（idcard）、邮箱（email）、电话（mobile）三者必备其一，用于颁发证书
		Person person = new Person(userName);
		person.setMobile(cellphone);

		//设置身份证件信息
		PaperType pt = PaperType.OTHER;
		if(SystemCodeEnum.IDTY1.getCode().equalsIgnoreCase(depositDTO.getCertificatesType())){
			pt = PaperType.IDCARD;
		} else if(SystemCodeEnum.IDTY3.getCode().equalsIgnoreCase(depositDTO.getCertificatesType())){
			pt = PaperType.PASSPORT;
		}
		person.setPaper(pt, depositDTO.getCertificatesId());

		//创建个人印章
		//		SealService sealService = this.sealService(sdkClient);
		//		String sealData = sealService.generateSeal(person);
		Stamper personKeywordStamper = new Stamper(propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_PERSON_PAGE, Integer.class, null),
				propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_PERSON_OFFSETX, Float.class, null),
				propertyResolverSeal.getProperty(COORDINATE_DEPOSIT_PERSON_OFFSETY, Float.class, null));
		logger.info("手签base64" + localSignDTO.getPersonSealData());
		localSignService.sign(personStamperInput, personStamperOut,person,localSignDTO.getPersonSealData(),personKeywordStamper);
		//		localSignService.sign(personStamperInput, personStamperOut, person, sealData, personKeywordStamper);
		logger.info("个人签署有外观签名完成.");
		//========================================================================
		//完成签署
		InputStream inputStream = new FileInputStream(new File(localPersonStamperFileFullPath));
		OutputStream outputStream = new FileOutputStream(new File(localFullPath));
		localSignService.complete(inputStream, outputStream);

		if (null != inputStream)
		{
			inputStream.close();
		}

		if (null != outputStream)
		{
			outputStream.close();
		}

		logger.info("合同签署已完成。");
		pdf2ImageIconDeposit(depositDTO, localFullPath, localPath);
		return remoteFullPath;
	}

	@Async
	private void pdf2ImageIconDeposit(DepositDTO depositDTO, String localFullPath, String localPath)
			throws IOException, BusinessException {
		// PDF转图片，并覆盖原图片
		Integer depositId = depositDTO.getId();
		FileDTO depositImage = depositDTO.getImage();
		String imageLocalFullPath = depositImage.getLocalFullPath();

		PDF2Image.createImg(localFullPath, imageLocalFullPath);
		// 图片加水印，并覆盖原图片
		String iconName =  propertyResolverSeal.getProperty(ICON_NAME, String.class, null);
		String iconPath = localPath + "/" + iconName;
		for (int i = 0; i < 2; i++) {
			IconImage.markImageByIcon(iconPath, imageLocalFullPath, imageLocalFullPath, null, iconPositionWidth, iconPpositionHeight * i);
		}
		Deposit deposit = new Deposit();
		deposit.setId(depositId);
		deposit.setChapter(true);
		depositService.update(deposit);
	}

	private String localSignContract(LocalSignDTO localSignDTO) throws BusinessException,IOException {
		Integer contractId = localSignDTO.getContractId();
		ContractDTO contractDTO = (ContractDTO) contractService.get(contractId);
		if(contractDTO.getOriginalCId()!=null && !StringUtils.isEmpty(contractDTO.getRentType())){
			 Contract contractA = contractReadMapper.selectByPrimaryKey(contractDTO.getOriginalCId());
			 if(StringUtils.isEmpty(contractA.getRentStatus())){
				 throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.CHANGE_CONTRACTA_IS_NOTCONFIRM.getDesc(),contractA.getContractNo()));
			 }
		}
		Integer prjId = contractDTO.getProjectId();
		ConfigurationQiyuesuo configurationQiyuesuo = (ConfigurationQiyuesuo) configurationQiyuesuoServiceImpl.get(prjId);
		if (configurationQiyuesuo == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.CONFIGURATION_QIYUESUO_ERROE);
		}
		String accessToken = configurationQiyuesuo.getAccessToken();
		String accessSecret = configurationQiyuesuo.getAccessSecret();
		Long sealId = configurationQiyuesuo.getSealId();
		if (StringUtils.isBlank(accessToken)
				|| StringUtils.isBlank(accessSecret)
				|| sealId == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.CONFIGURATION_QIYUESUO_ERROE);
		}
		SDKClient sdkClient = this.sdkClient(accessToken, accessSecret);
		LocalSignService localSignService = this.LocalSignService(sdkClient);
		FileDTO contractPdf = contractDTO.getPdf();
		String localFullPath = contractPdf.getLocalFullPath();
		String remoteFullPath = contractPdf.getFullPath();
		String userName = contractDTO.getCertificatesName();
		String cellphone = contractDTO.getCellphone();
		String contractPath = propertyResolverFile.getProperty(CONTRACT_PATH, String.class, null);
		String localPath = propertyResolverFile.getProperty(LOCAL_PATH, String.class, null);
		String localFilePath = localPath + "/" + contractPath + "/";
		//平台签署有外观签名
		InputStream platformStamperInput = new FileInputStream(new File(localFullPath));
		String localPlatFormStamperFileName = "qiyuesuo-local-platform-stamper.pdf";
		String localPlatFormStamperFileFullPath = localFilePath + localPlatFormStamperFileName;
		OutputStream platformStamperOut = new FileOutputStream(new File(localPlatFormStamperFileFullPath));
		//指定签名页码和坐标，确定签名位置
		//Stamper stamper = new Stamper(1, 0.1f, 0.1f);
		//根据关键字确定签名位置，若找到多个关键字则只在第一个关键字出现的位置签署，若没有出现关键字则抛出异常
		Stamper keywordStamper = new Stamper(propertyResolverSeal.getProperty(COORDINATE_CONTRACT_COMPANY_PAGE, Integer.class, null),
				propertyResolverSeal.getProperty(COORDINATE_CONTRACT_COMPANY_OFFSETX, Float.class, null),
				propertyResolverSeal.getProperty(COORDINATE_CONTRACT_COMPANY_OFFSETY, Float.class, null));
//			Long sealId = propertyResolverSeal.getProperty(SEAL_ID, Long.class, null);//印章ID，在云平台维护
		localSignService.sign(platformStamperInput, platformStamperOut,sealId ,keywordStamper);
		logger.info("平台签署带外观签名完成.");
		//========================================================================
		//个人用户签署有外观签名
		String localPersonStamperFileName = "qiyuesuo-local-person-stamper.pdf";
		String localPersonStamperFileFullPath = localFilePath + localPersonStamperFileName;
		InputStream personStamperInput = new FileInputStream(new File(localPlatFormStamperFileFullPath));
		OutputStream personStamperOut = new FileOutputStream(new File(localPersonStamperFileFullPath));
		//实例化个人用户信息，姓名（name）必须, 身份信息（idcard）、邮箱（email）、电话（mobile）三者必备其一，用于颁发证书
		Person person = new Person(userName);
		person.setMobile(cellphone);

		//设置身份证件信息
		PaperType pt = PaperType.OTHER;
		if(SystemCodeEnum.IDTY1.getCode().equalsIgnoreCase(contractDTO.getCertificatesType())){
			pt = PaperType.IDCARD;
		} else if(SystemCodeEnum.IDTY3.getCode().equalsIgnoreCase(contractDTO.getCertificatesType())){
			pt = PaperType.PASSPORT;
		}
		person.setPaper(pt, contractDTO.getCertificatesId());

		//创建个人印章
		//	SealService sealService = this.sealService(sdkClient);
		//	String sealData = sealService.generateSeal(person);
		Stamper personKeywordStamper = new Stamper(propertyResolverSeal.getProperty(COORDINATE_CONTRACT_PERSON_PAGE, Integer.class, null),
				propertyResolverSeal.getProperty(COORDINATE_CONTRACT_PERSON_OFFSETX, Float.class, null),
				propertyResolverSeal.getProperty(COORDINATE_CONTRACT_PERSON_OFFSETY, Float.class, null));
		localSignService.sign(personStamperInput, personStamperOut,person,localSignDTO.getPersonSealData(),personKeywordStamper);
		//	localSignService.sign(personStamperInput, personStamperOut, person, sealData, personKeywordStamper);
		logger.info("个人签署有外观签名完成.");
		//========================================================================
		//完成签署
		InputStream inputStream = new FileInputStream(new File(localPersonStamperFileFullPath));
		OutputStream outputStream = new FileOutputStream(new File(localFullPath));
		localSignService.complete(inputStream, outputStream);
		logger.info("合同签署已完成。");

		if (null != inputStream)
		{
			inputStream.close();
		}

		if (null != outputStream)
		{
			outputStream.close();
		}

		pdf2ImageIconContract(contractDTO, localFullPath, localPath);
		return remoteFullPath;
	}

	@Async
	private void pdf2ImageIconContract(ContractDTO contractDTO, String localFullPath, String localPath)
			throws IOException, BusinessException {
		// PDF转图片，并覆盖原图片
		Integer contractId = contractDTO.getId();
		FileDTO contractImage = contractDTO.getImage();
		String imageLocalFullPath = contractImage.getLocalFullPath();
		PDF2Image.createImg(localFullPath, imageLocalFullPath);
		// 图片加水印，并覆盖原图片
		String iconName =  propertyResolverSeal.getProperty(ICON_NAME, String.class, null);
		String iconPath = localPath + "/" + iconName;
		for (int i = 0; i < 7; i++) {
			IconImage.markImageByIcon(iconPath, imageLocalFullPath, imageLocalFullPath, null, iconPositionWidth, iconPpositionHeight * i);
		}
		Contract contract = new Contract();
		contract.setId(contractId);
		contract.setIsChapter(true);
		contractService.update(contract);
	}

	@Override
	public String localSign(LocalSignDTO localSignDTO) throws BusinessException, IOException {
		String fileRemoteFullPath = null;
		String personSealData = localSignDTO.getPersonSealData();
		Integer contractId = localSignDTO.getContractId();
		Integer depositId = localSignDTO.getDepositId();
		if (personSealData != null) {
			logger.info("ersonSealData.getBytes().length "+personSealData.getBytes().length);
			logger.info("PersonSealData original "+personSealData);
			if (personSealData.getBytes().length > 20480) {
				String localPath = propertyResolverFile.getProperty(LOCAL_PATH, String.class, null);
				String localFilePath = localPath + "/" + "sealImage.jpg";
				ImageZip.generateImage(personSealData, localFilePath);
				ImageZip.zipImageFile(new File(localFilePath), new File(localFilePath), 400, 0, 0.5f);
				//ImageZip.zipImageFile(new File(localFilePath), new File(localFilePath), 100, 0, 0.7f);
				String imageStr = ImageZip.getImageStr(localFilePath);
				logger.info("imageStr original "+imageStr);

				if (imageStr != null) {
					String nextStr = imageStr.replaceAll("\r|\n", "");
					if(nextStr.getBytes().length > 20480){
						logger.info("签字文件过大 大于20480");
						throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_SIGN_FILE_IS_BIG);
					}
					localSignDTO.setPersonSealData(nextStr);
				}
			}
			logger.info("PersonSealData now "+localSignDTO.getPersonSealData());
			if (contractId != null) {
				fileRemoteFullPath = this.localSignContract(localSignDTO);
			} else if (depositId != null) {
				fileRemoteFullPath = this.localSignDeposit(localSignDTO);
			}
		}
		return fileRemoteFullPath;
	}


	@Override
	public void setEnvironment(Environment environment) {
		propertyResolverSeal = new RelaxedPropertyResolver(environment, ENV_SEAL);
		propertyResolverFile = new RelaxedPropertyResolver(environment, ENV_FILE_PATH);
	}

	public HashMap<String, Object> localSignConfirmation(VerificationCode verificationcode)
			throws BusinessException
	{
		HashMap<String, Object> map = new HashMap<String, Object>();
		try {
			// 校验验证码

			VerificationCode verification = new VerificationCode();
			verification.setCellPhone(verificationcode.getCellPhone());
			verification.setVerificationCode(verificationcode.getVerificationCode());
			verification.setOper(SendMsgCodeEnum.signConfirmation.getCode());
			sendSmsService.checkVerification(verification);
			map.put("status", 0);
		}
		catch (LandseaBusinessException e)
		{
			map.put("status", -3);
			map.put("msg", "验证码错误！");
		}
		return map;
	}

	@Override
	public void testLocalSign(LocalSignDTOTest localSignDTO) throws BusinessException, FileNotFoundException, IOException {
		String fileRemoteFullPath = null;
		String personSealData = localSignDTO.getPersonSealData();
		Integer contractId = localSignDTO.getContractId();
		Integer depositId = localSignDTO.getDepositId();
		if (personSealData != null) {
			logger.info("ersonSealData.getBytes().length "+personSealData.getBytes().length);
			logger.info("PersonSealData original "+personSealData);
			if (personSealData.getBytes().length > 20480) {
				String localPath = propertyResolverFile.getProperty(LOCAL_PATH, String.class, null);
				String localFilePath = localPath + "/" + "sealImagetest.jpg";
				ImageZip.generateImage(personSealData, localFilePath);
				ImageZip.zipImageFile(new File(localFilePath), new File(localFilePath), localSignDTO.getWidth(),
						localSignDTO.getHeight(), localSignDTO.getQuality());
				String imageStr = ImageZip.getImageStr(localFilePath);
				logger.info("imageStr original "+imageStr);

				if (imageStr != null) {
					String nextStr = imageStr.replaceAll("\r|\n", "");
					localSignDTO.setPersonSealData(nextStr);
				}
			}
			//logger.info("PersonSealData now "+localSignDTO.getPersonSealData());
		}
	}

}